package abc.base;

import abc.config.MybatisPlusAutoFillConfig;
import abc.database.DataExecuor;
import abc.config.DatasourceConfigure;
import abc.model.DSInfo;
import abc.utils.StringUtil;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.*;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

@Slf4j
public abstract class BaseGenerator {

    @Autowired
    protected DatasourceConfigure datasourceConfigure;

    @Autowired
    protected MybatisPlusAutoFillConfig autoFillConfig;

    @Autowired
    protected DataExecuor dataExecuor;

    protected int runningCount = 0;

    public BaseGenerator() {}

    public BaseGenerator(DatasourceConfigure datasourceConfigure, MybatisPlusAutoFillConfig mybatisPlusAutoFillConfig) {
        this.datasourceConfigure = datasourceConfigure;
        this.autoFillConfig = mybatisPlusAutoFillConfig;
    }

    private static InputStream getSqlConfigStream() throws FileNotFoundException {
        File file = new File(System.getProperty("user.dir") + File.separator+"src"+File.separator+"main"+File.separator+"resources"+File.separator+"sql"+File.separator+"init.sql");
        if(file.exists()) {
            return new FileInputStream(file);
        }
        else {
            return BaseGenerator.class.getResourceAsStream("/sql/init.sql");
        }
    }

    /**
     * 执行数据库脚本
     */
    protected static void initDataSource(DataSourceConfig dataSourceConfig) throws SQLException, FileNotFoundException {
        Connection conn = dataSourceConfig.getConn();
        InputStream inputStream = getSqlConfigStream();
        ScriptRunner scriptRunner = new ScriptRunner(conn);
        scriptRunner.setAutoCommit(true);
        scriptRunner.runScript(new InputStreamReader(inputStream));
        conn.close();
    }

    /**
     * 策略配置
     */
    protected StrategyConfig.Builder strategyConfig() {
        return new StrategyConfig.Builder();
    }

    /**
     * 全局配置
     */
    protected GlobalConfig.Builder globalConfig() {
        return new GlobalConfig.Builder();
    }

    /**
     * 包配置
     */
    protected PackageConfig.Builder packageConfig() {
        return new PackageConfig.Builder();
    }

    /**
     * 模板配置
     */
    protected TemplateConfig.Builder templateConfig() {
        return new TemplateConfig.Builder();
    }

    /**
     * 注入配置
     */
    protected InjectionConfig.Builder injectionConfig() {
        // 测试自定义输出文件之前注入操作，该操作再执行生成代码前 debug 查看
        return new InjectionConfig.Builder().beforeOutputFile((tableInfo, objectMap) -> {
            System.out.println("tableInfo: " + tableInfo.getEntityName() + " objectMap: " + objectMap.size());
        });
    }

    public void run() {
        if(datasourceConfigure == null ||
                datasourceConfigure.getDatasource() == null ||
                datasourceConfigure.getDatasource().entrySet().size()<1) {
            log.warn("Can not find the datasource config!!!");
            return;
        }
        if(dataExecuor == null) {
            dataExecuor = new DataExecuor(datasourceConfigure);
        }
        for(Map.Entry<String, DSInfo> config : datasourceConfigure.getDatasource().entrySet()) {
            runningCount++;
            DataSourceConfig.Builder configBuilder = new DataSourceConfig.Builder(
                    config.getValue().getUrl(),
                    config.getValue().getUsername(),
                    config.getValue().getPassword());
            try {
                // 初始化数据库脚本
                initDataSource(configBuilder
                        .typeConvert(new MySqlTypeConvert())
                        .keyWordsHandler(new MySqlKeyWordsHandler())
                        .build()
                );
                List<String> list = StringUtil.splitString2List(config.getValue().getUrl(), "/");
                String dbname = list.get(list.size()-1);
                var columns = dataExecuor.getCloumns(dbname);
                build(configBuilder, dataExecuor.getTableMap(dbname), columns, config.getKey(), dbname);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    protected abstract void build(DataSourceConfig.Builder configBuilder, Map<String, Map<String, Object>> tablesMap, List<Map<String, Object>> columns, String datasourceName, String dbname) throws Exception;
}
